package iot.disruptor;

import com.lmax.disruptor.AlertException;
import com.lmax.disruptor.Sequence;
import com.lmax.disruptor.SequenceBarrier;
import com.lmax.disruptor.WaitStrategy;

import java.util.concurrent.locks.LockSupport;

/**
 * Created by dave on 18-8-14 上午10:34.
 */
public class TimedWaitStrategy implements WaitStrategy {
    private final int retries;
    private final long sleepTimeNs;
    private final long timeoutInMilles;
    private final DisruptorQueue queue;

    public TimedWaitStrategy(DisruptorQueue queue, int retries, long sleepTimeNs, long timeoutInMilles) {
        this.queue = queue;
        this.retries = retries;
        this.sleepTimeNs = sleepTimeNs;
        this.timeoutInMilles = timeoutInMilles;
    }

    @Override
    public long waitFor(
            final long sequence, Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier)
            throws AlertException {
        long availableSequence;
        int counter = retries;

        long t1 = System.nanoTime();
        long t2;
        while ((availableSequence = dependentSequence.get()) < sequence) {
            t2 = System.nanoTime();
            if (t2 - t1 > timeoutInMilles * 1000_000) {
                t1 = t2;
                queue.flush();
            }
            counter = applyWaitMethod(barrier, counter);
        }

        return availableSequence;
    }

    @Override
    public void signalAllWhenBlocking() {
    }

    private int applyWaitMethod(final SequenceBarrier barrier, int counter)
            throws AlertException {
        barrier.checkAlert();

        if (counter > 0) {
            --counter;
            Thread.yield();
        } else {
            LockSupport.parkNanos(sleepTimeNs);
        }

        return counter;
    }
}
